package net.java.mediasystems.database.core.model;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Table;

@Entity
@Table(name = "MEDIA_ITEM")
public class MediaItem implements Serializable {
	
	public static final int MAX_TITLE_LENGTH = 120;
	public static final int MAX_DESCRIPTION_LENGTH = 2000;
	
	private static final long serialVersionUID = 7872630705610646025L;
	
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name ="ID")
	private Long id;
	
	@Column(name ="TITLE", nullable = false)
	private String title;
	
	@Enumerated(EnumType.STRING)
	@Column(name = "MEDIA_TYPE", nullable = false)
	private MediaType mediaType;
	
	@Column(name = "DESCRIPTION")
	private String description;
	
	@Column(name = "RELEASE_DATE")
	private Date releaseDate;	// TODO discuss, if we should only store the release-year into an int-value
	
	@Column(name ="TRAILER_LINK")
	private String trailerLink;
	
	@ManyToOne(optional = false)
	private MediaQuality mediaQuality;
	
	@ManyToOne(optional = false)
	private StorageContainer storageContainer;
	
	//@OneToMany(mappedBy = "mediaItem")
	//List<MediaItemToGenreAssociation> genres;
	@ManyToMany
	@JoinTable(
			name="GENRE_TO_MEDIA_ITEM",
			joinColumns={@JoinColumn(name="MEDIA_ITEM_ID", referencedColumnName="ID")},
			inverseJoinColumns={@JoinColumn(name="GENRE_ID", referencedColumnName="ID")}
	)
	List<Genre> genres;
	
	// Unidirectional One-To-Many-Mapping with a Join-Table
	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	@JoinTable(name = "PICTURE_TO_MEDIA_ITEM",
		joinColumns={ 
			@JoinColumn(name="MEDIA_ITEM_ID", referencedColumnName="ID")
		},
	    inverseJoinColumns={
			@JoinColumn(name="PICTURE_ID", referencedColumnName="ID", unique=true)
		}
	)
	private List<Picture> pictures;
	
	@OneToMany(mappedBy = "mediaItem")
	private List<MetadataValue> metadataValues;
	
	@Column(name = "INSERTED_DATE")
	private Date insertedDate;
	
	@Column(name = "UPDATED_DATE")
	private Date updatedDate;
	
	@PrePersist
	private void onCreate() {
		this.insertedDate = new Date();
	}
	
	@PreUpdate
	private void onUpdate() {
		this.updatedDate = new Date();
	}
	
	@Override
	public int hashCode() {
		final int prime = 43;
		int result = 1;
		
		result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
		return result;
	}
	
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		MediaItem other = (MediaItem) obj;
		if (id == null) {
			if (other.id != null) {
				return false;
			}
		} else if (!id.equals(other.id)) {
			return false;
		}
		return true;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public MediaType getMediaType() {
		return mediaType;
	}

	public void setMediaType(MediaType mediaType) {
		this.mediaType = mediaType;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public Date getReleaseDate() {
		return releaseDate;
	}

	public void setReleaseDate(Date releaseDate) {
		this.releaseDate = releaseDate;
	}

	public String getTrailerLink() {
		return trailerLink;
	}

	public void setTrailerLink(String trailerLink) {
		this.trailerLink = trailerLink;
	}

	public MediaQuality getMediaQuality() {
		return mediaQuality;
	}

	public void setMediaQuality(MediaQuality mediaQuality) {
		this.mediaQuality = mediaQuality;
	}

	public StorageContainer getStorageContainer() {
		return storageContainer;
	}

	public void setStorageContainer(StorageContainer storageContainer) {
		this.storageContainer = storageContainer;
	}

//	public List<MediaItemToGenreAssociation> getGenres() {
//		return genres;
//	}
//
//	public void setGenres(List<MediaItemToGenreAssociation> genres) {
//		this.genres = genres;
//	}
	
	public List<Genre> getGenres() {
		return genres;
	}

	public void setGenres(List<Genre> genres) {
		this.genres = genres;
	}
	

	public List<Picture> getPictures() {
		return pictures;
	}
	public void setPictures(List<Picture> pictures) {
		this.pictures = pictures;
	}

	public List<MetadataValue> getMetadataValues() {
		return metadataValues;
	}

	public void setMetadataValues(List<MetadataValue> metadataValues) {
		this.metadataValues = metadataValues;
	}

	public Date getInsertedDate() {
		return insertedDate;
	}

	public Date getUpdatedDate() {
		return updatedDate;
	}
}
